package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.tanhua.autoconfig.template.HuanXinTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.commons.utils.UserHolder;
import com.tanhua.domain.Question;
import com.tanhua.domain.UserInfo;
import com.tanhua.dto.RecommendUserDto;
import com.tanhua.dubbo.api.*;
import com.tanhua.mongo.RecommendUser;
import com.tanhua.mongo.UserLocation;
import com.tanhua.mongo.Visitors;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.vo.ErrorResult;
import com.tanhua.vo.NearUserVo;
import com.tanhua.vo.PageResult;
import com.tanhua.vo.TodayBest;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 交友 服务消费者
 */
@Service
public class TanhuaService {
    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private QuestionApi questionApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @Value("${tanhua.default.recommend.users}")
    private String recommendUserIds;

    @DubboReference
    private UserLikeApi userLikeApi;

    @Autowired
    private MessageService messageService;

    @DubboReference
    private UserLocationApi userLocationApi;

    @DubboReference
    private VisitorsApi visitorsApi;

    /**
     * 指定泛型避免不必要的错误
     */
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    public TodayBest RecommendTodayBest() {
        //获取被推荐人id
        Long userId = UserHolder.getUserId();
        //返回今日佳人
        RecommendUser recommendUser = recommendUserApi.RecommendMaxScore(userId);
        //为空自动推荐
        if (recommendUser == null) {
            recommendUser = new RecommendUser();
            recommendUser.setUserId(1L);
            recommendUser.setScore(99D);
        }
        //获取推荐人的信息
        UserInfo info = userInfoApi.findById(recommendUser.getUserId());

        //封装为vo对象
        TodayBest vo = TodayBest.init(info, recommendUser);
        return vo;
    }

    /**
     * 推荐好友具体实现
     * 1，获取用户id
     * 2，根据被推荐人toUserId去推荐表查询具体的推荐数据（PageResult对象）
     * PageResult中包含page,pagesize,count,recommendUsers
     * 3，判断recommendUsers是否为空，为空直接返回PageResult对象
     * 4，如果recommendUsers不是为空，根据recommendUsers中的推荐人id查询到具体的UserInfo数据
     * 5，优化，通过CollUtil.getFieldValues工具封装ids数组对象
     * 6，userInfoMapper方法findByIds，封装map（UserInfo.getId，UserInfo）对象返回
     * 需要进行条件判断（年龄，性别）
     * 7，对recommendUsers中每个对象item，通过他的推荐人UserId在map中查询对应的UserInfo对象
     * 并将item和userInfo封装为TodayBest对象，存入数组返回
     * 8，为PageResult设置items，返回PageResult
     *
     * @param dto
     * @return
     */
    public PageResult recommendation(RecommendUserDto dto) {
        //获取被推荐人id
        Long userId = UserHolder.getUserId();
        //获取推荐的分页查询表
        PageResult pageResult = recommendUserApi.recommendUserList(dto.getPage(), dto.getPagesize(), userId);

        List<RecommendUser> items = (List<RecommendUser>) pageResult.getItems();
        //将recommendUserList中的userId数据封装
        if (items == null || items.size() == 0) {
            //推荐好友列表为空，直接返回
            return pageResult;
        }
        //批量获取推荐用户数据表
        List<Long> ids = CollUtil.getFieldValues(items, "userId", Long.class);
        UserInfo userInfo = new UserInfo();
        userInfo.setGender(dto.getGender());
        userInfo.setAge(dto.getAge());
        //map中key为用户id，值为userInfo对象
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids, userInfo);
        //将原本的item数据变为TodayBest对象
        ArrayList<TodayBest> arrayList = new ArrayList();
        for (RecommendUser item : items) {
            UserInfo info = map.get(item.getUserId());
            if (info != null) {
                TodayBest todayBest = TodayBest.init(info, item);
                arrayList.add(todayBest);
            }
        }
        //设置pageResult中的item
        pageResult.setItems(arrayList);
        return pageResult;
    }

    /**
     * 查询佳人信息
     *
     * @param userId
     * @return
     */
    public TodayBest personInfo(Long userId) {
        //查询用户详情
        UserInfo userInfo = userInfoApi.findById(userId);
        //通过被查询人id和查询用户id获取缘分值
        RecommendUser recommendUser = recommendUserApi.queryRecommend(userId, UserHolder.getUserId());
        RecommendUser user = recommendUserApi.queryRecommend(UserHolder.getUserId(), userId);
        //封装访客信息并保存
        Visitors visitors = new Visitors();
        visitors.setUserId(userId);
        visitors.setVisitorUserId(UserHolder.getUserId());
        visitors.setFrom("首页");
        visitors.setDate(System.currentTimeMillis());
        visitors.setVisitDate(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        visitors.setScore(user.getScore());
        visitorsApi.save(visitors);
        //封装todayBest返回
        return TodayBest.init(userInfo, recommendUser);
    }

    /**
     * 查询陌生人问题
     * @param userId
     * @return
     */
    public String strangerQuestions(Long userId) {
        //获取对应陌生人问题信息
        Question question = questionApi.getByUserId(userId);
        //Question对象可能为null,设置默认陌生人问题
        return question == null ? "你喜欢鲜花吗？" : question.getTxt();
    }

    /**
     * 回复陌生人问题
     * @param userId
     * @param reply
     * @return
     */
    public void answerQuestion(Long userId, String reply) {
        //构造消息数据格式
        Long currentUserId = UserHolder.getUserId();
        UserInfo userInfo = userInfoApi.findById(currentUserId);
        //构建回复陌生人消息格式map
        Map map = new HashMap();
        map.put("userId", currentUserId);
        map.put("huanXinId", Constants.HX_USER_PREFIX+currentUserId);
        map.put("nickname", userInfo.getNickname());
        map.put("strangerQuestions", strangerQuestions(userId));
        map.put("reply", reply);
        //转为JSON格式
        String jsonString = JSON.toJSONString(map);
        //调用环信发送信息
        Boolean aBoolean = huanXinTemplate.sendMsg(Constants.HX_USER_PREFIX + userId, jsonString);
        if(!aBoolean){
            //未发送出消息则抛出错误
            throw new BusinessException(ErrorResult.error());
        }
    }

    /**
     * 返回探花-左滑右滑列表
     * @return
     */
    public List<TodayBest> cards() {
        //调用api查询推荐列表（要排除已喜欢或不喜欢的）
        List<RecommendUser> recommendUserList = recommendUserApi.queryRecommendList(UserHolder.getUserId());
        //判断是否为空，为空自动推荐优化用户体验
        if(recommendUserList == null || recommendUserList.size() == 0){
            recommendUserList = new ArrayList<>();
            String[] userIdS = recommendUserIds.split(",");
            for (String userId : userIdS) {
                RecommendUser recommendUser = new RecommendUser();
                recommendUser.setUserId(Long.valueOf(userId));
                recommendUser.setToUserId(UserHolder.getUserId());
                recommendUser.setScore(RandomUtil.randomDouble(60D,99D));
                recommendUserList.add(recommendUser);
            }
        }
        //收集recommend对象的id
        List<Long> ids = CollUtil.getFieldValues(recommendUserList, "userId", Long.class);
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids, null);
        //封装TodayBest对象返回
        ArrayList<TodayBest> todayBestList = new ArrayList<>();
        for (RecommendUser item : recommendUserList) {
            UserInfo userInfo = map.get(item.getUserId());
            if(userInfo != null){
                TodayBest todayBest = TodayBest.init(userInfo, item);
                todayBestList.add(todayBest);
            }
        }
        return todayBestList;
    }

    /**
     * 探花-喜欢
     * @param likeUserId
     */
    public void love(Long likeUserId) {
        //调用api，保存喜欢数据（保存到mongodb中）
        Boolean flag = userLikeApi.saveOrUpdate(UserHolder.getUserId(),likeUserId,true);
        //保存失败抛出错误
        if(!flag){
            throw new BusinessException(ErrorResult.error());
        }
        //操作redis，写入喜欢的数据，删除不喜欢的数据
        redisTemplate.opsForSet().remove(Constants.USER_NOT_LIKE_KEY+UserHolder.getUserId(),likeUserId.toString());
        redisTemplate.opsForSet().add(Constants.USER_LIKE_KEY+UserHolder.getUserId(),likeUserId.toString());
        //判断是否是双向喜欢
        if(isLikeToo(likeUserId,UserHolder.getUserId())){
            //添加好友
            messageService.contacts(likeUserId);
        }
    }

    /**
     * 探花-不喜欢
     * @param likeUserId
     */
    public void unLove(Long likeUserId) {
        //调用api，保存不喜欢数据（保存到mongodb中）
        Boolean flag = userLikeApi.saveOrUpdate(UserHolder.getUserId(),likeUserId,false);
        //保存失败抛出错误
        if(!flag){
            throw new BusinessException(ErrorResult.error());
        }
        //操作redis，写入喜欢的数据，删除不喜欢的数据
        redisTemplate.opsForSet().remove(Constants.USER_LIKE_KEY+UserHolder.getUserId(),likeUserId.toString());
        redisTemplate.opsForSet().add(Constants.USER_NOT_LIKE_KEY+UserHolder.getUserId(),likeUserId.toString());
    }

    /**
     * 判断是否是双向喜欢,抽取公共方法
     * @param userId
     * @param likeUserId
     * @return
     */
    public Boolean isLikeToo(Long userId,Long likeUserId){
        String key = Constants.USER_LIKE_KEY+userId;
        return redisTemplate.opsForSet().isMember(key,likeUserId.toString());
    }


    /**
     * 搜附近
     * @param gender
     * @param distance
     * @return
     */
    public List<NearUserVo> search(String gender, String distance) {
        //通过api查询范围内的其他用户
        List<UserLocation> list = userLocationApi.search(UserHolder.getUserId(),gender,Double.valueOf(distance));
        //判断集合是否非空
        if(list == null || list.size() == 0){
            return new ArrayList<>();
        }
        //排除自己
        list = list.stream().filter(item -> {return item.getUserId().equals(UserHolder.getUserId());
        }).collect(Collectors.toList());
        //拼接nearUserVo对象
        List<Long> ids = CollUtil.getFieldValues(list, "userId", Long.class);
        UserInfo info = new UserInfo();
        info.setGender(gender);
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids, info);
        ArrayList<NearUserVo> arrayList = new ArrayList();
        for (UserLocation userLocation : list) {
            UserInfo userInfo = map.get(userLocation.getUserId());
            if(userInfo != null){
                NearUserVo vo = NearUserVo.init(userInfo);
                arrayList.add(vo);
            }
        }
        //返回
        return arrayList;
    }
}
